package project1;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>人机对弈</p>
 * @see Gomoku
 */
@Gomoku_Component("人机对弈模式")
public class GomokuAI {
    DrawGomoku dg;
    @Interface_component("记录玩家棋子威胁分数的列表")
    List<D_chess> player_chess = new ArrayList<D_chess>();
    @Interface_component("记录AI棋子进攻分数的列表")
    List<D_chess> AI_chess = new ArrayList<D_chess>();

    public GomokuAI(DrawGomoku dg) {
        this.dg = dg;
    }

    public GomokuAI() {}


    @Interface_event(event = "AI下棋")
/*
   如果AI_chess为空，执行第一步落子
   否则，根据威胁分数和进攻分数，选择最优的下法
   @param bestDefense 最优的防守位置
   @param bestAttack 最优的进攻位置
  优先防守，其次进攻
 */
    public void  move(){
        player_chess.clear();
        AI_chess.clear();
        if(dg.AI_chess.isEmpty()){
            makeFirstMove();
            return;
        }

        defend();
        attack();

        D_chess bestDefense = null;
        for(D_chess d : player_chess)
            if(bestDefense == null || bestDefense.score < d.score)
                bestDefense = d;


        D_chess bestAttack = null;
        for(D_chess d : AI_chess)
            if(bestAttack == null || bestAttack.score < d.score)
                bestAttack = d;

        if(bestDefense != null&&bestDefense.score>=100){
            makeDefendMove(bestDefense);
        }else if(bestAttack!=null&&bestAttack.score>=100){
            makeAttackMove(bestAttack);
        }else if(bestDefense!=null&&bestDefense.score>=50){
            makeDefendMove(bestDefense);
        }else if(bestAttack!=null&&bestAttack.score>=50){
            makeAttackMove(bestAttack);
        }else if(bestDefense!=null&&bestDefense.score>=20){
            makeDefendMove(bestDefense);
        }else if(bestAttack!=null&&bestAttack.score>=20){
            makeAttackMove(bestAttack);
        }else{
            if(bestAttack!=null&&(bestDefense==null || bestDefense.score<bestAttack.score)){
                makeAttackMove(bestAttack);
            }else if(bestDefense!=null){
                makeDefendMove(bestDefense);
            }else{
                Random_chess();
            }
        }



    }
    @Interface_event(event="评估防守棋子的分数")
    public void defend() {
        for (Point p : dg.Player_chess) {
            //把棋盘坐标转换为网格坐标
            int[] grid = dg.board_grid(p);
            int x = grid[0];
            int y = grid[1];
            checkDefend(x, y, 1, 0, dg.Player_chess);
            checkDefend(x, y, -1, 0, dg.Player_chess);
            checkDefend(x, y, 0, 1, dg.Player_chess);
            checkDefend(x, y, 0, -1, dg.Player_chess);
            checkDefend(x, y, 1, 1, dg.Player_chess);
            checkDefend(x, y, 1, -1, dg.Player_chess);
            checkDefend(x, y, -1, 1, dg.Player_chess);
            checkDefend(x, y, -1, -1, dg.Player_chess);
        }
    }

    @Interface_event(event= "评估估进攻棋子的分数")
    //进攻功能
    public void attack() {
        if (dg.AI_chess.isEmpty()) {
            boolean x = makeFirstMove();
            return;
        }
        //检查每个AI棋子的进攻机会
        for (Point p : dg.AI_chess) {
            //将棋盘坐标转为网格坐标
            int[] grid = dg.board_grid(p);
            int x = grid[0];
            int y = grid[1];
            checkAttack(x, y, 1, 0, dg.AI_chess);
            checkAttack(x, y, -1, 0, dg.AI_chess);
            checkAttack(x, y, 0, 1, dg.AI_chess);
            checkAttack(x, y, 0, -1, dg.AI_chess);
            checkAttack(x, y, 1, 1, dg.AI_chess);
            checkAttack(x, y, 1, -1, dg.AI_chess);
            checkAttack(x, y, -1, 1, dg.AI_chess);
            checkAttack(x, y, -1, -1, dg.AI_chess);
        }

    }


    @Interface_event(event= "第一步落子")
    private boolean makeFirstMove(){
        //如果棋盘中心空着，优先占据中心
        if(!isPointOccupied(8,8,dg.Player_chess, dg.AI_chess)){
            addAIchess(8,8);
            return true;
        }

        //如果中心被占据，选择中心周围的策略位置
        int[][] strategicPositions ={
                {6,7},{8,7},{7,6},{7,8},
                {6,6},{6,8},{7,6},{7,8},
                {5,7},{9,7},{7,5},{7,9}
        };

        for(int[] p: strategicPositions){
            if(!isPointOccupied(p[0],p[1],dg.Player_chess, dg.AI_chess)){
                addAIchess(p[0],p[1]);
                return true;
            }
        }
        Random_chess();
        return true;
    }

    /**
     * <p>防守功能的实现</p>
     * @param points 玩家棋子的列表
     * 1.连成4个连续的玩家棋子，必须防守
     * 2.连成3个连续的玩家棋子，防守阻碍玩家连成4个连续的棋子，两端都需要防守
     * 3.三连威胁，防守1个棋子
     * 4.二连威胁，防守1个棋子
     * */
    //检查每个玩家棋子的威胁情况
    public void checkDefend(int x, int y, int dx, int dy, List<Point> points) {
        @Interface_component("检查正方向连续的玩家棋子数量")
        int forwardCount = countConsecutive(x, y, dx, dy, points);
        @Interface_component("检查反方向连续的玩家棋子数量")
        int backwardCount = countConsecutive(x, y, -dx, -dy, points);
        int totalCount = forwardCount + backwardCount;


        if (totalCount >= 4) {
            addDefendPosition(x + (forwardCount + 1) * dx, y + (forwardCount + 1) * dy, 100);
            addDefendPosition(x - (backwardCount + 1) * dx, y - (backwardCount + 1) * dy, 100);
        }
        //四连威胁
        else if (totalCount == 3) {
            addDefendPosition(x + (forwardCount + 1) * dx, y + (forwardCount + 1) * dy, 50);
            addDefendPosition(x - (backwardCount + 1) * dx, y - (backwardCount + 1) * dy, 50);
        }
        //三
        else if (totalCount == 2) {
            addDefendPosition(x + (forwardCount + 1) * dx, y + (forwardCount + 1) * dy, 20);
            addDefendPosition(x - (backwardCount + 1) * dx, y - (backwardCount + 1) * dy, 20);
        }
        //二连威胁
        else if (totalCount == 1) {
            addDefendPosition(x + (forwardCount + 1) * dx, y + (forwardCount + 1) * dy, 5);
            addDefendPosition(x - (backwardCount + 1) * dx, y - (backwardCount + 1) * dy, 5);
        }


    }
    //把威胁棋子的下一个棋子添加到player_chess中
    private void addDefendPosition(int x, int y, int score) {
        if (isInBoard(x, y) && !isPointOccupied(x, y, dg.Player_chess, dg.AI_chess)) {
            //dc添加的是网格坐标
            D_chess dc = new D_chess(x, y);
            dc.addScore(score);
            player_chess.add(dc);
        }
    }

    //防卫时下棋
    public void makeDefendMove(D_chess dc) {
        //直接在指定位置落子
        if (isInBoard(dc.x, dc.y) && !isPointOccupied(dc.x, dc.y, dg.Player_chess, dg.AI_chess)) {
            addAIchess(dc.x, dc.y);
            return;
        }
        //尝试该棋子的周围8个位置
        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}};
        for (int[] dir : directions) {
            int newX = dc.x + dir[0];
            int newY = dc.y + dir[1];
            if (isInBoard(newX, newY) && !isPointOccupied(newX, newY, dg.Player_chess, dg.AI_chess)) {
                addAIchess(newX, newY);
                return;
            }
        }
        Random_chess();
    }



//以下是进攻功能的实现
    //检查每个AI棋子的进攻机会
    private void checkAttack(int x,int y,int dx,int dy,List<Point> points){
        //计算正方向的连续棋子数
        int forwardCount = countConsecutive(x,y,dx,dy, points);
        //计算反方向的连续棋子数
        int  backwardCount = countConsecutive(x,y,-dx,-dy, points);
        //总连续棋子数
        int totalCount = backwardCount + forwardCount;

        int X1 = x+dx*(forwardCount+1);
        int Y1 = y+dy*(forwardCount+1);
        int X2 = x-dx*(backwardCount+1);
        int Y2 = y-dy*(backwardCount+1);

        if(isPointOccupied(X1,Y1,dg.Player_chess, dg.AI_chess)){}
        boolean forwardBlocked = !isInBoard(X1,Y1)||isPointOccupied(X1,Y1, dg.Player_chess, dg.AI_chess);
        boolean backwardBlocked = !isInBoard(X2,Y2)||isPointOccupied(X2,Y2, dg.Player_chess, dg.AI_chess);

        //根据连续棋子数和阻挡情况确定进攻等级位置
        if(totalCount>=4) {
            addAttackPosition(X1,Y1,100);
            addAttackPosition(X2,Y2,100);
        }
        else if(totalCount==3) {
            addAttackPosition(X1,Y1,50);
            addAttackPosition(X2,Y2,50);
        }
        else if(totalCount==2) {
            addAttackPosition(X1,Y1,20);
            addAttackPosition(X2,Y2,20);
        }
        else if(totalCount==1) {
            addAttackPosition(X1,Y1,10);
            addAttackPosition(X2,Y2,10);
        }
    }

    //添加进攻位置
    private void addAttackPosition(int x,int y,int score){
        if(isInBoard(x,y)&&!isPointOccupied(x,y,dg.Player_chess, dg.AI_chess)){
            D_chess dc = new D_chess(x,y);
            dc.addScore(score);
            AI_chess.add(dc);
        }
    }

    //执行进攻落子
    private void makeAttackMove(D_chess dc) {
        //直接在指定位置落子
        if(isInBoard(dc.x,dc.y)&&!isPointOccupied(dc.x,dc.y, dg.Player_chess, dg.AI_chess)){
            addAIchess(dc.x,dc.y);
            return;
        }

        //如果首选位置不可用，尝试周围8个位置
        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}};
        for (int[] dir : directions) {
            int newX = dc.x + dir[0];
            int newY = dc.y + dir[1];
            if (isInBoard(newX, newY) && !isPointOccupied(newX, newY, dg.Player_chess, dg.AI_chess)) {
                addAIchess(newX, newY);
                return;
            }
        }
        Random_chess();
    }

    //随机落子
    public void Random_chess() {
        int attempts = 0;
        while (attempts < 100) {
            int x = (int) (Math.random() * 15 + 1);
            int y = (int) (Math.random() * 15 + 1);
            if (!isPointOccupied(x,y, dg.Player_chess, dg.AI_chess)){
                addAIchess(x, y);
                return;
            }
            attempts++;
        }

        if (attempts >= 100) {
            for(int i=1;i<=15;i++){
                for(int j=1;j<=15;j++){
                    if(!isPointOccupied(i,j, dg.Player_chess, dg.AI_chess)){
                        addAIchess(i,j);
                        return;
                    }
                }
            }
        }
    }

    //添加AI棋子
    public void addAIchess(int x, int y) {
        //x、y是网格坐标，转换成棋盘坐标
        int board[] = dg.grid_board(x, y);
        x = board[0];
        y = board[1];
        dg.AI_chess.add(new Point(x, y));
        dg.repaint();

    }

    //计算连续棋子数
    public int countConsecutive(int x, int y, int dx, int dy, List<Point> points) {
        int count = 0;
        int checkX = x + dx;
        int checkY = y + dy;
        //检查最多四个位置
        for (int i = 0; i < 4; i++) {
            if (isInBoard(checkX, checkY) && dg.isSameColor(checkX, checkY, points)) {
                count++;
                checkX += dx;
                checkY += dy;
            } else
                break;

        }
        return count;

    }

    //检查点是否在棋盘内
    private boolean isInBoard(int x, int y) {
        //网格坐标
        return x >= 1 && x <= 15 && y >= 1 && y <= 15;
    }

    //检查点是否被占用
    private boolean isPointOccupied(int x, int y, List<Point> points1, List<Point> points2) {
        int[] board = dg.grid_board(x, y);
        x = board[0];
        y = board[1];
        for (Point p : points1) {
            if (p.x == x && p.y == y)
                return true;
        }
        for (Point p : points2) {
            if (p.x == x && p.y == y)
                return true;
        }
        return false;
    }

}

